/* Copyright 2009 (c) ENSI de Bourges
 * 		88 boulevard Lahitolle, 18020 Bourges Cedex, France
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * \file table-utilities.c
 * \brief Source code for the functions related to LiveSecurity's frames table
 * \author Steve Dodier <sidnioulz@gmail.com>
 * \author Timothée Ravier <timothee.ravier.romain@gmail.com>
 *
 * This source code file contains functions useful for manipulating the GtkTable
 * containing all the frames in LiveSecurity's GUI.
 */
#include <gtk/gtk.h>
#include <math.h>

#include "application-data.h"
#include "frame-utilities.h"
#include "table-utilities.h"



frame_t *slot_data_get (guint rows, guint cols)
{
	ls_instance_t	*inst	= livesecurity_instance (0);
	guint			table_cols;
	g_object_get (inst->table, "n-columns", &table_cols, NULL);
	return inst->slot_data[table_cols*rows + cols];
}

void slot_data_set (guint rows, guint cols, frame_t *elem)
{
	ls_instance_t	*inst	= livesecurity_instance (0);
	guint			table_cols;
	g_object_get (inst->table, "n-columns", &table_cols, NULL);
	g_print ("Data slot: %d,%d set !\n", rows, cols);
	inst->slot_data[table_cols * rows + cols] = elem;
}

int slot_data_find_empty_slot (guint *rows, guint *cols, guint size_x, guint size_y)
{
	ls_instance_t	*inst	= livesecurity_instance (0);
	guint			table_rows, table_cols;
	
	g_object_get (inst->table, "n-columns", &table_cols, "n-rows", &table_rows, NULL);
	g_print ("Table is %d,%d wide.\n", table_rows, table_cols);

	while ( (*rows) < table_rows ) {
		g_print ("Looking at: %d,%d\n", *rows, *cols);
		if ( slot_data_get (*rows, *cols) == NULL ) {
			//TODO regarder la taille des frames
			return 0;
		}
		else {
			if ( (*cols) == (table_cols-1) ) {
				(*cols) = 0;
				(*rows)++;
			}
			else {
				(*cols)++;
			}
		}
	}
	return 1;
	//TODO while < table(cols*rows) && != null ++
	
	//Recherche une place pour une frame.
	//Retourne 0 si libre (avec les coordonées pointées par les params), 1 sinon.
	return 1;
}

int slot_data_resize (guint old_rows, guint old_cols, guint rows, guint cols)
{
	ls_instance_t	*inst	= livesecurity_instance (0);
	inst->slot_data = g_realloc (inst->slot_data, sizeof (frame_t*) * rows*cols);
	
	guint i,j;
	for (i = 0; i < rows; i++) {
		for (j = old_cols; j < cols; j++) {
			inst->slot_data[cols * i + j] = NULL;
		}
	}
	for (i = old_rows; i < rows; i++) {
		for (j = 0; j < old_cols; j++) {
			inst->slot_data[cols * i + j] = NULL;
		}
	}
	return 0;
}

int table_frame_size_changed (GtkWidget *table, frame_t *elem, guint old_size_x, guint old_size_y, guint new_size_x, guint new_size_y)
{
	//TODO large frames management (all resizing / placing algorithms)
	return 0;
}

int table_get_optimal_nb_cols (GtkTable *table)
{
	return 3; //FIXME implement
	//TODO obtenir le nombre de small frame que l'on peut positionner en largeur
}

int table_get_optimal_nb_rows (GtkTable *table)
{
	return 2; //FIXME implement
	//TODO obtenir le nombre de small frame que l'on peut positionner en hauteur
}

int table_size_changed (GtkTable *table)
{
	ls_instance_t	*inst	= livesecurity_instance (0);
	guint			table_rows, table_cols;
	guint 			optimal_rows, optimal_cols;
	
	g_object_get (inst->table, "n-columns", &table_cols, "n-rows", &table_rows, NULL);
		
	optimal_rows = table_get_optimal_nb_rows (table);
	optimal_cols = table_get_optimal_nb_cols (table);
	//TODO attention si pas de resize !
	
	gtk_table_resize (table, optimal_rows, optimal_cols);
	slot_data_resize (table_rows, table_cols, optimal_rows, optimal_cols);	
	
	g_print ("The table is now resized to (%d,%d).\n", optimal_rows, optimal_cols);
	
	return 0;
}

int table_add (GtkWidget *table, frame_t *elem)
{
	ls_instance_t	*inst	= livesecurity_instance (0);
	guint 			columns, rows;
	guint			size_x, size_y;
	
	table_size_changed (GTK_TABLE(table)); //FIXME Signal_conect...
	
	inst->children_size[elem->size]++;
	
	size_x = ((elem->size == NORMAL) ? NORMAL_WIDTH_SLOTS : LARGE_WIDTH_SLOTS);
	size_y = ((elem->size == NORMAL) ? NORMAL_HEIGHT_SLOTS : LARGE_HEIGHT_SLOTS);
	columns=0;
	rows=0;
	if (!slot_data_find_empty_slot (&rows, &columns, size_x, size_y)) {
		gtk_table_attach_defaults (GTK_TABLE (table), frame_get_root_widget (elem), columns, columns+1, rows, rows+1);
		//FIXME Lorsque la gestion des tailles sera ok, remplacer par: columns, columns+size_x, rows, rows+size_y
		g_print ("Table slot: %d,%d set !\n", rows, columns);
		slot_data_set (rows, columns, elem); //TODO regarder la taille
	}
	else {
		g_print ("Plus de place, la frame va dans la liste.\n"); //TODO implement list
	}
	
	return 0;
}


int table_remove (GtkWidget *table, frame_t *elem)
{
	GtkWidget		*elemwidget	= frame_get_root_widget (elem);
	ls_instance_t	*inst		= livesecurity_instance (0);
	//GValue			val			= {0,};
	int				top = 0, left = 0;
	guint			table_rows, table_cols;
	
	g_object_get (inst->table, "n-columns", &table_cols, "n-rows", &table_rows, NULL);
	
/*	gtk_container_child_get_property (GTK_CONTAINER (table), elemwidget, "top-attach", &val);*/
/*	top = g_value_get_int (&val);*/
/*	g_value_unset (&val);*/
/*	*/
/*	gtk_container_child_get_property (GTK_CONTAINER (table), elemwidget, "left-attach", &val);*/
/*	left = g_value_get_int (&val);*/
/*	g_value_unset (&val);*/
	
	while (slot_data_get (top, left) != elem ) {
		g_print ("Looking at: %d,%d\n", top, left);
		if (top < table_rows) {
			if (left == (table_cols-1)) {
				left = 0;
				top++;
			}
			else {
				left++;
			}
		}
		else {
			g_print ("The frame you're trying to remove doesn't exist !\n");
			return 1;
		}
	}
	
	//TODO regarder la taille des frames
	
	g_print ("Data slot: %d,%d removed !\n",top ,left);
	slot_data_set (top, left, NULL);
	
	g_object_ref (elemwidget);
	gtk_container_remove (GTK_CONTAINER (table), elemwidget);
	inst->children_size[elem->size]--;
	
	return 0;
}

int table_swap_children (GtkWidget *table, frame_t *child1, frame_t *child2)
{
	//guint	child1_col, child1_row, child2_col, child2_row;
	
	//frame_t *slot_data_get (guint rows, guint cols)
	//void slot_data_set (guint rows, guint cols, frame_t *elem)
	
	return 0;
}

//table_size_up
//table_size_down
